home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / src / cmd.c < prev    next >
C/C++ Source or Header  |  1993-01-22  |  27KB  |  1,142 lines

  1. /*    SCCS Id: @(#)cmd.c    3.1    92/11/25    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. #include "hack.h"
  6. #include "func_tab.h"
  7.  
  8. /*
  9.  * Some systems may have getchar() return EOF for various reasons, and
  10.  * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
  11.  */
  12. #if defined(SYSV) || defined(DGUX) || defined(HPUX)
  13. #define    NR_OF_EOFS    20
  14. #endif
  15.  
  16. #ifdef DUMB    /* stuff commented out in extern.h, but needed here */
  17. extern int NDECL(doapply); /**/
  18. extern int NDECL(dorub); /**/
  19. extern int NDECL(dojump); /**/
  20. extern int NDECL(doextlist); /**/
  21. extern int NDECL(dodrop); /**/
  22. extern int NDECL(doddrop); /**/
  23. extern int NDECL(dodown); /**/
  24. extern int NDECL(doup); /**/
  25. extern int NDECL(donull); /**/
  26. extern int NDECL(dowipe); /**/
  27. extern int NDECL(do_mname); /**/
  28. extern int NDECL(ddocall); /**/
  29. extern int NDECL(dotakeoff); /**/
  30. extern int NDECL(doremring); /**/
  31. extern int NDECL(dowear); /**/
  32. extern int NDECL(doputon); /**/
  33. extern int NDECL(doddoremarm); /**/
  34. extern int NDECL(dokick); /**/
  35. extern int NDECL(dothrow); /**/
  36. extern int NDECL(doeat); /**/
  37. extern int NDECL(done2); /**/
  38. extern int NDECL(doengrave); /**/
  39. extern int NDECL(dopickup); /**/
  40. extern int NDECL(ddoinv); /**/
  41. extern int NDECL(dotypeinv); /**/
  42. extern int NDECL(dolook); /**/
  43. extern int NDECL(doprgold); /**/
  44. extern int NDECL(doprwep); /**/
  45. extern int NDECL(doprarm); /**/
  46. extern int NDECL(doprring); /**/
  47. extern int NDECL(dopramulet); /**/
  48. extern int NDECL(doprtool); /**/
  49. extern int NDECL(dosuspend); /**/
  50. extern int NDECL(doforce); /**/
  51. extern int NDECL(doopen); /**/
  52. extern int NDECL(doclose); /**/
  53. extern int NDECL(dosh); /**/
  54. extern int NDECL(dodiscovered); /**/
  55. extern int NDECL(doset); /**/
  56. extern int NDECL(dotogglepickup); /**/
  57. extern int NDECL(dowhatis); /**/
  58. extern int NDECL(doquickwhatis); /**/
  59. extern int NDECL(dowhatdoes); /**/
  60. extern int NDECL(dohelp); /**/
  61. extern int NDECL(dohistory); /**/
  62. extern int NDECL(doloot); /**/
  63. extern int NDECL(dodrink); /**/
  64. extern int NDECL(dodip); /**/
  65. extern int NDECL(dosacrifice); /**/
  66. extern int NDECL(dopray); /**/
  67. extern int NDECL(doturn); /**/
  68. extern int NDECL(doredraw); /**/
  69. extern int NDECL(doread); /**/
  70. extern int NDECL(dosave); /**/
  71. extern int NDECL(dosearch); /**/
  72. extern int NDECL(doidtrap); /**/
  73. extern int NDECL(dopay); /**/
  74. extern int NDECL(dosit); /**/
  75. extern int NDECL(dotalk); /**/
  76. extern int NDECL(docast); /**/
  77. extern int NDECL(dovspell); /**/
  78. extern int NDECL(dotele); /**/
  79. extern int NDECL(dountrap); /**/
  80. extern int NDECL(doversion); /**/
  81. extern int NDECL(doextversion); /**/
  82. extern int NDECL(dowield); /**/
  83. extern int NDECL(dozap); /**/
  84. extern int NDECL(doorganize); /**/
  85. #endif /* DUMB */
  86.  
  87. #ifdef OVL1
  88. static int NDECL((*timed_occ_fn));
  89. #endif /* OVL1 */
  90.  
  91. STATIC_PTR int NDECL(doprev_message);
  92. STATIC_PTR int NDECL(timed_occupation);
  93. STATIC_PTR int NDECL(doextcmd);
  94. # ifdef POLYSELF
  95. STATIC_PTR int NDECL(domonability);
  96. # endif
  97. # ifdef WIZARD
  98. STATIC_PTR int NDECL(wiz_wish);
  99. STATIC_PTR int NDECL(wiz_identify);
  100. STATIC_PTR int NDECL(wiz_map);
  101. STATIC_PTR int NDECL(wiz_genesis);
  102. STATIC_PTR int NDECL(wiz_where);
  103. STATIC_PTR int NDECL(wiz_detect);
  104. STATIC_PTR int NDECL(wiz_level_tele);
  105. # endif
  106. # ifdef EXPLORE_MODE
  107. STATIC_PTR int NDECL(enter_explore_mode);
  108. # endif
  109. # if defined(WIZARD) || defined(EXPLORE_MODE)
  110. STATIC_PTR int NDECL(wiz_attributes);
  111. # endif
  112.  
  113. #ifdef OVLB
  114. static void FDECL(enlght_line, (const char *,const char *,const char *));
  115. #ifdef UNIX
  116. static void NDECL(end_of_input);
  117. #endif
  118. #endif /* OVLB */
  119.  
  120. #ifdef OVL0
  121. static int FDECL(click_to_cmd, (int,int,int));
  122. #endif /* OVL0 */
  123.  
  124. STATIC_OVL char *NDECL(parse);
  125.  
  126. #ifdef UNIX
  127. extern boolean hu;
  128. #endif
  129.  
  130. #ifdef OVL1
  131.  
  132. STATIC_PTR int
  133. doprev_message()
  134. {
  135.     return nh_doprev_message();
  136. }
  137.  
  138. /* Count down by decrementing multi */
  139. STATIC_PTR int
  140. timed_occupation() {
  141.     (*timed_occ_fn)();
  142.     if (multi > 0)
  143.         multi--;
  144.     return multi > 0;
  145. }
  146.  
  147. /* If you have moved since initially setting some occupations, they
  148.  * now shouldn't be able to restart.
  149.  *
  150.  * The basic rule is that if you are carrying it, you can continue
  151.  * since it is with you.  If you are acting on something at a distance,
  152.  * your orientation to it must have changed when you moved.
  153.  *
  154.  * The exception to this is taking off items, since they can be taken
  155.  * off in a number of ways in the intervening time, screwing up ordering.
  156.  *
  157.  *    Currently:    Take off all armor.
  158.  *            Picking Locks / Forcing Chests.
  159.  */
  160. void
  161. reset_occupations() {
  162.  
  163.     reset_remarm();
  164.     reset_pick();
  165. }
  166.  
  167. /* If a time is given, use it to timeout this function, otherwise the
  168.  * function times out by its own means.
  169.  */
  170. void
  171. set_occupation(fn, txt, xtime)
  172. int NDECL((*fn));
  173. const char *txt;
  174. int xtime;
  175. {
  176.     if (xtime) {
  177.         occupation = timed_occupation;
  178.         timed_occ_fn = fn;
  179.     } else
  180.         occupation = fn;
  181.     occtxt = txt;
  182.     occtime = 0;
  183.     return;
  184. }
  185.  
  186. #ifdef REDO
  187.  
  188. static char NDECL(popch);
  189.  
  190. /* Provide a means to redo the last command.  The flag `in_doagain' is set
  191.  * to true while redoing the command.  This flag is tested in commands that
  192.  * require additional input (like `throw' which requires a thing and a
  193.  * direction), and the input prompt is not shown.  Also, while in_doagain is
  194.  * TRUE, no keystrokes can be saved into the saveq.
  195.  */
  196. #define BSIZE 20
  197. static char pushq[BSIZE], saveq[BSIZE];
  198. static int NEARDATA phead, NEARDATA ptail, NEARDATA shead, NEARDATA stail;
  199.  
  200. static char
  201. popch() {
  202.     /* If occupied, return '\0', letting tgetch know a character should
  203.      * be read from the keyboard.  If the character read is not the
  204.      * ABORT character (as checked in pcmain.c), that character will be
  205.      * pushed back on the pushq.
  206.      */
  207.     if (occupation) return '\0';
  208.     if (in_doagain) return (shead != stail) ? saveq[stail++] : '\0';
  209.     else        return (phead != ptail) ? pushq[ptail++] : '\0';
  210. }
  211.  
  212. char
  213. pgetchar() {        /* curtesy of aeb@cwi.nl */
  214.     register int ch;
  215.  
  216.     if(!(ch = popch()))
  217.         ch = nhgetch();
  218.     return(ch);
  219. }
  220.  
  221. /* A ch == 0 resets the pushq */
  222. void
  223. pushch(ch)
  224. char ch;
  225. {
  226.     if (!ch)
  227.         phead = ptail = 0;
  228.     if (phead < BSIZE)
  229.         pushq[phead++] = ch;
  230.     return;
  231. }
  232.  
  233. /* A ch == 0 resets the saveq.    Only save keystrokes when not
  234.  * replaying a previous command.
  235.  */
  236. void
  237. savech(ch)
  238. char ch;
  239. {
  240.     if (!in_doagain) {
  241.         if (!ch)
  242.             phead = ptail = shead = stail = 0;
  243.         else if (shead < BSIZE)
  244.             saveq[shead++] = ch;
  245.     }
  246.     return;
  247. }
  248. #endif /* REDO */
  249.  
  250. #endif /* OVL1 */
  251. #ifdef OVLB
  252.  
  253. STATIC_PTR int
  254. doextcmd()    /* here after # - now read a full-word command */
  255. {
  256.     char buf[BUFSZ];
  257.     register const struct ext_func_tab *efp = extcmdlist;
  258. again:
  259. #ifdef COM_COMPL
  260.     get_ext_cmd(buf);
  261. #else
  262.     getlin("#", buf);
  263. #endif
  264.     clear_nhwindow(WIN_MESSAGE);
  265.     if(buf[0] == '\0' || buf[0] == '\033')
  266.         return 0;
  267.     if(buf[0] == '?') {
  268.         (void) doextlist();
  269.         goto again;
  270.     }
  271.     while(efp->ef_txt) {
  272.         if(!strncmpi(efp->ef_txt, buf,BUFSIZ))
  273.             return (*(efp->ef_funct))();
  274.         efp++;
  275.     }
  276.     pline("%s: unknown extended command.", buf);
  277.     return 0;
  278. }
  279.  
  280. int
  281. doextlist()    /* here after #? - now list all full-word commands */
  282. {
  283.     register const struct ext_func_tab *efp;
  284.     char     buf[BUFSZ];
  285.     winid datawin;
  286.  
  287.     datawin = create_nhwindow(NHW_TEXT);
  288.     putstr(datawin, 0, "");
  289.     putstr(datawin, 0, "            Extended Commands List");
  290.     putstr(datawin, 0, "");
  291. #ifdef COM_COMPL
  292.     putstr(datawin, 0, "    Press '#', then type (first letter only):");
  293. #else
  294.     putstr(datawin, 0, "    Press '#', then type:");
  295. #endif
  296.     putstr(datawin, 0, "");
  297.  
  298.     for(efp = extcmdlist; efp->ef_txt; efp++) {
  299.         Sprintf(buf, "    %-8s  - %s.", efp->ef_txt, efp->ef_desc);
  300.         putstr(datawin, 0, buf);
  301.     }
  302.     display_nhwindow(datawin, FALSE);
  303.     destroy_nhwindow(datawin);
  304.     return 0;
  305. }
  306.  
  307. #ifdef POLYSELF
  308. STATIC_PTR int
  309. domonability()
  310. {
  311.     if (can_breathe(uasmon)) return dobreathe();
  312.     else if (attacktype(uasmon, AT_SPIT)) return dospit();
  313.     else if (u.usym == S_NYMPH) return doremove();
  314.     else if (u.usym == S_UMBER) return doconfuse();
  315.     else if (is_were(uasmon)) return dosummon();
  316.     else if (webmaker(uasmon)) return dospinweb();
  317.     else if (is_hider(uasmon)) return dohide();
  318.     else if(u.umonnum == PM_GREMLIN) {
  319.         if(IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
  320.         struct monst *mtmp;
  321.         if ((mtmp = cloneu()) != 0) {
  322.             mtmp->mhpmax = (u.mhmax /= 2);
  323.             You("multiply.");
  324.             dryup(u.ux,u.uy);
  325.         }
  326.         } else pline("There is no fountain here.");
  327.     }
  328.     else if (u.usym == S_UNICORN) {
  329.         use_unicorn_horn((struct obj *)0);
  330.         return 1;
  331.     } else if (u.umonnum == PM_MIND_FLAYER) return domindblast();
  332.     else if (uasmon->msound == MS_SHRIEK) {
  333.         You("shriek.");
  334.         aggravate();
  335.     } else if (u.umonnum >= 0)
  336.         pline("Any special ability you may have is purely reflexive.");
  337.     else You("don't have a special ability!");
  338.     return 0;
  339. }
  340. #endif
  341.  
  342. #ifdef EXPLORE_MODE
  343. STATIC_PTR int
  344. enter_explore_mode()
  345. {
  346.     if(!discover && !wizard) {
  347.         pline("Beware!  From discovery mode there will be no return to normal game.");
  348.         if (yn("Do you want to enter discovery mode?") == 'y') {
  349.             clear_nhwindow(WIN_MESSAGE);
  350.             You("are now in non-scoring discovery mode.");
  351.             discover = TRUE;
  352.         }
  353.         else {
  354.             clear_nhwindow(WIN_MESSAGE);
  355.             pline("Resuming normal game.");
  356.         }
  357.     }
  358.     return 0;
  359. }
  360. #endif
  361.  
  362. #ifdef WIZARD
  363. STATIC_PTR int
  364. wiz_wish()    /* Unlimited wishes for debug mode by Paul Polderman */
  365. {
  366.     if (wizard) {
  367.         makewish();
  368.         (void) encumber_msg();
  369.     } else
  370.         pline("Unavailable command '^W'.");
  371.     return 0;
  372. }
  373.  
  374. STATIC_PTR int
  375. wiz_identify()
  376. {
  377.     struct obj *obj;
  378.  
  379.     if (!wizard)
  380.         pline("Unavailable command '^I'.");
  381.     else {
  382.         for (obj = invent; obj; obj = obj->nobj)
  383.             if (!objects[obj->otyp].oc_name_known || !obj->known
  384.                         || !obj->dknown || !obj->bknown)
  385.                 (void) identify(obj);
  386.     }
  387.     return 0;
  388. }
  389.  
  390. STATIC_PTR int
  391. wiz_map()
  392. {
  393.     if (wizard)    do_mapping();
  394.     else        pline("Unavailable command '^F'.");
  395.     return 0;
  396. }
  397.  
  398. STATIC_PTR int
  399. wiz_genesis()
  400. {
  401.     if (wizard)    (void) create_particular();
  402.     else        pline("Unavailable command '^G'.");
  403.     return 0;
  404. }
  405.  
  406. STATIC_PTR int
  407. wiz_where()
  408. {
  409.     if (wizard) print_dungeon();
  410.     else        pline("Unavailable command '^O'.");
  411.     return 0;
  412. }
  413.  
  414. STATIC_PTR int
  415. wiz_detect()
  416. {
  417.     if(wizard)  (void) findit();
  418.     else        pline("Unavailable command '^E'.");
  419.     return 0;
  420. }
  421.  
  422. STATIC_PTR int
  423. wiz_level_tele()
  424. {
  425.     if (wizard)    level_tele();
  426.     else        pline("Unavailable command '^V'.");
  427.     return 0;
  428. }
  429.  
  430. #endif /* WIZARD */
  431.  
  432. /* -enlightenment- */
  433. static winid en_win;
  434. static const char
  435.     *You_ = "You ",
  436.     *are  = "are ",  *were  = "were ",
  437.     *have = "have ", *had   = "had ",
  438.     *can  = "can ",  *could = "could ";
  439.  
  440. #define enl_msg(prefix,present,past,suffix) \
  441.             enlght_line(prefix, final ? past : present, suffix)
  442. #define you_are(attr)    enl_msg(You_,are,were,attr)
  443. #define you_have(attr)    enl_msg(You_,have,had,attr)
  444. #define you_can(attr)    enl_msg(You_,can,could,attr)
  445.  
  446. static void
  447. enlght_line(start, middle, end)
  448. const char *start, *middle, *end;
  449. {
  450.     char buf[BUFSZ];
  451.  
  452.     Sprintf(buf, "%s%s%s.", start, middle, end);
  453.     putstr(en_win, 0, buf);
  454. }
  455.  
  456. void
  457. enlightenment(final)
  458. boolean final;
  459. {
  460.     int ltmp;
  461.     char buf[BUFSZ];
  462.  
  463.     en_win = create_nhwindow(NHW_MENU);
  464.     putstr(en_win, 0, final ? "Final Attributes:" : "Current Attributes:");
  465.     putstr(en_win, 0, "");
  466.  
  467.     /* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */
  468.     if (u.ualign.record >= 20)    you_are("piously aligned");
  469.     else if (u.ualign.record > 13)    you_are("devoutly aligned");
  470.     else if (u.ualign.record > 8)    you_are("fervently aligned");
  471.     else if (u.ualign.record > 3)    you_are("stridently aligned");
  472.     else if (u.ualign.record == 3)    you_are("aligned");
  473.     else if (u.ualign.record > 0)    you_are("haltingly aligned");
  474.     else if (u.ualign.record == 0)    you_are("nominally aligned");
  475.     else if (u.ualign.record >= -3)    you_have("strayed");
  476.     else if (u.ualign.record >= -8)    you_have("sinned");
  477.     else you_have("transgressed");
  478. #ifdef WIZARD
  479.     if (wizard) {
  480.         Sprintf(buf, " %d", u.ualign.record);
  481.         enl_msg("Your alignment ", "is", "was", buf);
  482.     }
  483. #endif
  484.  
  485.     if (Telepat) you_are("telepathic");
  486.     if (Searching) you_have("automatic searching");
  487.     if (Teleportation) you_can("teleport");
  488.     if (Teleport_control) you_have("teleport control");
  489.     if (See_invisible) enl_msg(You_, "see", "saw", " invisible");
  490.     if (Invisible) you_are("invisible");
  491.     else if (Invis) you_are("invisible to others");
  492.     if (Fast) you_are((Fast & ~INTRINSIC) ? "very fast" : "fast");
  493.     if (Stealth) you_are("stealthy");
  494.     if (Regeneration) enl_msg("You regenerate", "", "d", "");
  495.     if (Hunger) you_have("hunger");
  496.     if (Conflict) enl_msg("You cause", "", "d", " conflict");
  497.     if (Aggravate_monster) enl_msg("You aggravate", "", "d", " monsters");
  498.     if (Poison_resistance) you_are("poison resistant");
  499.     if (Fire_resistance) you_are("fire resistant");
  500.     if (Cold_resistance) you_are("cold resistant");
  501.     if (Shock_resistance) you_are("shock resistant");
  502.     if (Sleep_resistance) you_are("sleep resistant");
  503.     if (Disint_resistance) you_are("disintegration-resistant");
  504.     if (Protection_from_shape_changers)
  505.         you_are("protected from shape changers");
  506. #ifdef POLYSELF
  507.     if (Polymorph) you_are("polymorphing");
  508.     if (Polymorph_control) you_have("polymorph control");
  509. #endif
  510.     if (HHalluc_resistance)
  511.         enl_msg("You resist", "", "ed", " hallucinations");
  512.     if (final) {
  513.         if (Hallucination) you_are("hallucinating");
  514.         if (Stunned) you_are("stunned");
  515.         if (Confusion) you_are("confused");
  516.         if (Sick) you_are("sick");
  517.         if (Blinded) you_are("blinded");
  518.     }
  519.     if (Wounded_legs) {
  520.         Sprintf(buf, "wounded %s", makeplural(body_part(LEG)));
  521.         you_have(buf);
  522.     }
  523.     if (Glib) {
  524.         Sprintf(buf, "slippery %s", makeplural(body_part(FINGER)));
  525.         you_have(buf);
  526.     }
  527.     if (Strangled) you_are("being strangled");
  528.     if (Stoned) you_are("turning to stone");
  529.     if (Lifesaved)
  530.         enl_msg("Your life ", "will be", "would have been", " saved");
  531.     if (Adornment) you_are("adorned");
  532.     if (Warning) you_are("warned");
  533.     if (Protection) you_are("protected");
  534.     if (Reflecting) you_have("reflection");
  535.     if (Levitation) you_are("levitating");
  536.     if (Fumbling) enl_msg("You fumble", "", "d", "");
  537.     if (Jumping) you_can("jump");
  538.     if (Wwalking) you_can("walk on water");
  539.     if (Magical_breathing) you_can("survive without air");
  540.     if (Antimagic) you_are("magic-protected");
  541.     if (Displaced) you_are("displaced");
  542.     if (Clairvoyant) you_are("clairvoyant");
  543. #ifdef POLYSELF
  544.     if (u.ulycn != -1) {    
  545.         Strcpy(buf, an(mons[u.ulycn].mname));
  546.         you_are(buf);
  547.     }
  548. #endif
  549.     if (Luck) {
  550.         ltmp = abs((int)Luck);
  551.         Sprintf(buf, "%s%slucky",
  552.             ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "",
  553.             Luck < 0 ? "un" : "");
  554. #ifdef WIZARD
  555.         if (wizard) Sprintf(eos(buf), " (%d)", Luck);
  556. #endif
  557.         you_are(buf);
  558.     }
  559. #ifdef WIZARD
  560.      else if (wizard) enl_msg("Your luck ", "is", "was", " zero");
  561. #endif
  562.     ltmp = stone_luck(TRUE);
  563.     if (ltmp > 0) you_have("extra luck");
  564.     else if (ltmp < 0) you_have("reduced luck");
  565.     if (carrying(LUCKSTONE)) {
  566.         ltmp = stone_luck(FALSE);
  567.         if (ltmp <= 0)
  568.         enl_msg("Bad luck ", "does", "did", " not time out for you");
  569.         if (ltmp >= 0)
  570.         enl_msg("Good luck ", "does", "did", " not time out for you");
  571.     }
  572.  
  573.     display_nhwindow(en_win, TRUE);
  574.     destroy_nhwindow(en_win);
  575.     return;
  576. }
  577.  
  578. #if defined(WIZARD) || defined(EXPLORE_MODE)
  579. STATIC_PTR int
  580. wiz_attributes()
  581. {
  582.     if (wizard || discover)
  583.         enlightenment(FALSE);
  584.     else
  585.         pline("Unavailable command '^X'.");
  586.     return 0;
  587. }
  588. #endif /* WIZARD || EXPLORE_MODE */
  589.  
  590. #endif /* OVLB */
  591. #ifdef OVL1
  592.  
  593. #ifndef M
  594. # ifndef NHSTDC
  595. #  define M(c)        (0x80 | (c))
  596. # else
  597. #  define M(c)        ((c) - 128)
  598. # endif /* NHSTDC */
  599. #endif
  600. #ifndef C
  601. #define C(c)        (0x1f & (c))
  602. #endif
  603.  
  604. static const struct func_tab cmdlist[] = {
  605.     {C('d'), dokick},    /* "D" is for door!...? */
  606. #ifdef WIZARD
  607.     {C('e'), wiz_detect},
  608.     {C('f'), wiz_map},
  609.     {C('g'), wiz_genesis},
  610.     {C('i'), wiz_identify},
  611. #endif
  612.     {C('l'), doredraw}, /* if number_pad is set */
  613. #ifdef WIZARD
  614.     {C('o'), wiz_where},
  615. #endif
  616.     {C('p'), doprev_message},
  617.     {C('r'), doredraw},
  618.     {C('t'), dotele},
  619. #ifdef WIZARD
  620.     {C('v'), wiz_level_tele},
  621.     {C('w'), wiz_wish},
  622. #endif
  623. #if defined(WIZARD) || defined(EXPLORE_MODE)
  624.     {C('x'), wiz_attributes},
  625. #endif
  626. #ifdef SUSPEND
  627.     {C('z'), dosuspend},
  628. #endif
  629.     {'a', doapply},
  630.     {'A', doddoremarm},
  631.     {M('a'), doorganize},
  632. /*    'b', 'B' : go sw */
  633.     {'c', doclose},
  634.     {'C', do_mname},
  635.     {M('c'), dotalk},
  636.     {'d', dodrop},
  637.     {'D', doddrop},
  638.     {M('d'), dodip},
  639.     {'e', doeat},
  640.     {'E', doengrave},
  641. /* Soon to be
  642.     {'f', dofight, "fighting"},
  643.     {'F', doFight, "fighting"},
  644.  */
  645.     {M('f'), doforce},
  646. /*    'g', 'G' : multiple go */
  647. /*    'h', 'H' : go west */
  648.     {'h', dohelp}, /* if number_pad is set */
  649.     {'i', ddoinv},
  650.     {'I', dotypeinv},        /* Robert Viduya */
  651.     {M('i'), doinvoke},
  652. /*    'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */
  653.     {'j', dojump}, /* if number_pad is on */
  654.     {M('j'), dojump},
  655.     {'k', dokick}, /* if number_pad is on */
  656.     {'l', doloot}, /* if number_pad is on */
  657.     {M('l'), doloot},
  658. /*    'n' prefixes a count if number_pad is on */
  659. #ifdef POLYSELF
  660.     {M('m'), domonability},
  661. #endif /* POLYSELF */
  662.     {'N', ddocall}, /* if number_pad is on */
  663.     {M('N'), ddocall},
  664.     {'o', doopen},
  665.     {'O', doset},
  666.     {M('o'), dosacrifice},
  667.     {'p', dopay},
  668.     {'P', doputon},
  669.     {M('p'), dopray},
  670.     {'q', dodrink},
  671.     {'Q', done2},
  672.     {'r', doread},
  673.     {'R', doremring},
  674.     {M('r'), dorub},
  675.     {'s', dosearch, "searching"},
  676.     {'S', dosave},
  677.     {M('s'), dosit},
  678.     {'t', dothrow},
  679.     {'T', dotakeoff},
  680.     {M('t'), doturn},
  681. /*    'u', 'U' : go ne */
  682.     {'u', dountrap}, /* if number_pad is on */
  683.     {M('u'), dountrap},
  684.     {'v', doversion},
  685.     {'V', dohistory},
  686.     {M('v'), doextversion},
  687.     {'w', dowield},
  688.     {'W', dowear},
  689.     {M('w'), dowipe},
  690.     {'x', dovspell},            /* Mike Stephenson */
  691. #ifdef EXPLORE_MODE
  692.     {'X', enter_explore_mode},
  693. #endif
  694. /*    'y', 'Y' : go nw */
  695.     {'z', dozap},
  696.     {'Z', docast},
  697.     {'<', doup},
  698.     {'>', dodown},
  699.     {'/', dowhatis},
  700.     {'&', dowhatdoes},
  701.     {'?', dohelp},
  702. #ifdef SHELL
  703.     {'!', dosh},
  704. #endif
  705.     {'.', donull, "waiting"},
  706.     {' ', donull, "waiting"},
  707.     {',', dopickup},
  708.     {':', dolook},
  709.     {';', doquickwhatis},
  710.     {'^', doidtrap},
  711.     {'\\', dodiscovered},        /* Robert Viduya */
  712.     {'@', dotogglepickup},
  713.     {WEAPON_SYM,  doprwep},
  714.     {ARMOR_SYM,  doprarm},
  715.     {RING_SYM,  doprring},
  716.     {AMULET_SYM, dopramulet},
  717.     {TOOL_SYM, doprtool},
  718.     {GOLD_SYM, doprgold},
  719.     {SPBOOK_SYM, dovspell},            /* Mike Stephenson */
  720.     {'#', doextcmd},
  721.     {0,0,0}
  722. };
  723. #undef M
  724.  
  725. const struct ext_func_tab extcmdlist[] = {
  726.     {"adjust", "adjust inventory letters", doorganize},
  727.     {"chat", "talk to someone", dotalk},    /* converse? */
  728.     {"dip", "dip an object into something", dodip},
  729.     {"force", "force a lock", doforce},
  730.     {"invoke", "invoke an object's powers", doinvoke},
  731.     {"jump", "jump to a location", dojump},
  732.     {"loot", "loot a box on the floor", doloot},
  733. #ifdef POLYSELF
  734.     {"monster", "use a monster's special ability", domonability},
  735. #endif
  736.     {"name", "name an item or type of object", ddocall},
  737.     {"offer", "offer a sacrifice to the gods", dosacrifice},
  738.     {"pray", "pray to the gods for help", dopray},
  739.     {"rub", "rub a lamp", dorub},
  740.     {"sit", "sit down", dosit},
  741.     {"turn", "turn undead", doturn},
  742.     {"untrap", "untrap something", dountrap},
  743.     {"version", "list compile time options for this version of NetHack",
  744.         doextversion},
  745. #ifdef MAC
  746.     {"window", "clean up windows", SanePositions},
  747. #endif
  748.     {"wipe", "wipe off your face", dowipe},
  749.     {"?", "get this list of extended commands", doextlist},
  750.     {NULL, NULL, donull}
  751. };
  752.  
  753. #define unctrl(c)    ((c) <= C('z') ? (0x60 | (c)) : (c))
  754. #define unmeta(c)    (0x7f & (c))
  755.  
  756.  
  757. void
  758. rhack(cmd)
  759. register char *cmd;
  760. {
  761.     register const struct func_tab *tlist = cmdlist;
  762.     boolean firsttime = FALSE;
  763.     register int res;
  764.  
  765.     if(!cmd) {
  766.         firsttime = TRUE;
  767.         flags.nopick = 0;
  768.         cmd = parse();
  769.     }
  770.     if(*cmd == (char)033) {
  771.         flags.move = 0;
  772.         return;
  773.     }
  774. #ifdef REDO
  775.     if (*cmd == DOAGAIN && !in_doagain && saveq[0]) {
  776.         in_doagain = TRUE;
  777.         stail = 0;
  778.         rhack(NULL);    /* read and execute command */
  779.         in_doagain = FALSE;
  780.         return;
  781.     }
  782.     /* Special case of *cmd == ' ' handled better below */
  783.     if(!*cmd || *cmd == (char)0377) {
  784. #else
  785.     if(!*cmd || *cmd == (char)0377 ||
  786.        (!flags.rest_on_space && *cmd == ' ')) {
  787. #endif
  788.         nhbell();
  789.         flags.move = 0;
  790.         return;        /* probably we just had an interrupt */
  791.     }
  792.     if(movecmd(*cmd)) {
  793.     walk:
  794.         if(multi) flags.mv = 1;
  795.         domove();
  796.         return;
  797.     }
  798.     if(movecmd(flags.num_pad ? unmeta(*cmd) : lowc(*cmd))) {
  799.         flags.run = 1;
  800.     rush:
  801.         if(firsttime){
  802.             if(!multi) multi = COLNO;
  803.             u.last_str_turn = 0;
  804.         }
  805.         flags.mv = 1;
  806.         domove();
  807.         return;
  808.     }
  809.     if(*cmd == 'g' && movecmd(cmd[1])) {
  810.         flags.run = 2;
  811.         goto rush;
  812.     }
  813.     if (((*cmd == 'G' || (flags.num_pad && *cmd == '5')) &&
  814.         movecmd(lowc(cmd[1]))) || movecmd(unctrl(*cmd))) {
  815.         flags.run = 3;
  816.         goto rush;
  817.     }
  818.     if((*cmd == 'm' || (flags.num_pad && *cmd == '-')) &&
  819.         movecmd(cmd[1])) {
  820.         flags.run = 0;
  821.         flags.nopick = 1;
  822.         goto walk;
  823.     }
  824.     if(*cmd == 'M' && movecmd(lowc(cmd[1]))) {
  825.         flags.run = 1;
  826.         flags.nopick = 1;
  827.         goto rush;
  828.     }
  829.     if (flags.num_pad && *cmd == '0') {
  830.         (void)ddoinv();    /* A convenience borrowed from the PC */
  831.         flags.move = 0;
  832.         multi = 0;
  833.         return;
  834.     }
  835.     while(tlist->f_char) {
  836.         if((*cmd & 0xff) == (tlist->f_char & 0xff)){
  837.             /* Special case of *cmd == ' ' handled here */
  838.             if (*cmd == ' ' && !flags.rest_on_space)
  839.                 break;
  840.  
  841.             /* Now control-A can stop lengthy commands */
  842.             /* in the PC version only -- use ^C-N otherwise */
  843.             if (tlist->f_text && !occupation && multi)
  844. #ifdef GCC_WARN
  845.                 set_occupation(tlist->f_funct,
  846.                         tlist->f_text, multi);
  847. #else
  848.                 set_occupation(((struct func_tab *)tlist)->f_funct,
  849.                     tlist->f_text, multi);
  850. #endif
  851.             res = (*(tlist->f_funct))();
  852.             if(!res) {
  853.                 flags.move = 0;
  854.                 multi = 0;
  855.             }
  856.             return;
  857.         }
  858.         tlist++;
  859.     }
  860.     { char expcmd[10];
  861.       register char *cp = expcmd;
  862.       while(*cmd && cp-expcmd < sizeof(expcmd)-2) {
  863.         if(*cmd >= 040 && *cmd < 0177)
  864.             *cp++ = *cmd++;
  865.         else if (*cmd & 0200) {
  866.             *cp++ = 'M';
  867.             *cp++ = '-';
  868.             *cp++ = *cmd++ &=~ 0200;
  869.         }
  870.         else {
  871.             *cp++ = '^';
  872.             *cp++ = *cmd++ ^ 0100;
  873.         }
  874.       }
  875.       *cp = 0;
  876.       Norep("Unknown command '%s'.", expcmd);
  877.     }
  878.     multi = flags.move = 0;
  879.     return;
  880. }
  881.  
  882. int
  883. xytod(x, y)    /* convert an x,y pair into a direction code */
  884. schar x, y;
  885. {
  886.     register int dd;
  887.  
  888.     for(dd = 0; dd < 8; dd++)
  889.         if(x == xdir[dd] && y == ydir[dd]) return dd;
  890.  
  891.     return -1;
  892. }
  893.  
  894. #ifdef WALKIES
  895. void
  896. dtoxy(cc,dd)    /* convert a direction code into an x,y pair */
  897. coord *cc;
  898. register int dd;
  899. {
  900.     cc->x = xdir[dd];
  901.     cc->y = ydir[dd];
  902.     return;
  903. }
  904. #endif /* WALKIES */
  905.  
  906. int
  907. movecmd(sym)    /* also sets u.dz, but returns false for <> */
  908. char sym;
  909. {
  910.     register const char *dp;
  911.     register const char *sdp = flags.num_pad ? ndir : sdir;
  912.  
  913.     u.dz = 0;
  914.     if(!(dp = index(sdp, sym))) return 0;
  915.     u.dx = xdir[dp-sdp];
  916.     u.dy = ydir[dp-sdp];
  917.     u.dz = zdir[dp-sdp];
  918. #ifdef POLYSELF
  919.     if (u.dx && u.dy && u.umonnum == PM_GRID_BUG) {
  920.         u.dx = u.dy = 0;
  921.         return 0;
  922.     }
  923. #endif
  924.     return !u.dz;
  925. }
  926.  
  927. int
  928. getdir(s)
  929. const char *s;
  930. {
  931.     char dirsym;
  932.  
  933. #ifdef REDO    
  934.     if(in_doagain)
  935.         dirsym = readchar();
  936.     else
  937. #endif
  938.         dirsym = yn_function (s ? s : "In what direction?", NULL, '\0');
  939. #ifdef REDO
  940.     savech(dirsym);
  941. #endif
  942.     if(dirsym == '.' || dirsym == 's')
  943.         u.dx = u.dy = u.dz = 0;
  944.     else if(!movecmd(dirsym) && !u.dz) {
  945.         if(!index(quitchars, dirsym))
  946.             pline("What a strange direction!");
  947.         return 0;
  948.     }
  949.     if(!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir();
  950.     return 1;
  951. }
  952.  
  953. #endif /* OVL1 */
  954. #ifdef OVLB
  955.  
  956. void
  957. confdir()
  958. {
  959.     register int x =
  960. #ifdef POLYSELF
  961.         (u.umonnum == PM_GRID_BUG) ? 2*rn2(4) :
  962. #endif
  963.                             rn2(8);
  964.     u.dx = xdir[x];
  965.     u.dy = ydir[x];
  966.     return;
  967. }
  968.  
  969. #endif /* OVLB */
  970. #ifdef OVL0
  971.  
  972. int
  973. isok(x,y)
  974. register int x, y;
  975. {
  976.     /* x corresponds to curx, so x==1 is the first column. Ach. %% */
  977.     return x >= 1 && x <= COLNO-1 && y >= 0 && y <= ROWNO-1;
  978. }
  979.  
  980. static int NEARDATA last_multi;
  981.  
  982. /*
  983.  * convert a MAP window position into a movecmd
  984.  */
  985. static int
  986. click_to_cmd(x, y, mod)
  987.     int x, y, mod;
  988. {
  989.     x -= u.ux;
  990.     y -= u.uy;
  991.     /* convert without using floating point, allowing sloppy clicking */
  992.     if(x > 2*abs(y))
  993.     x = 1, y = 0;
  994.     else if(y > 2*abs(x))
  995.     x = 0, y = 1;
  996.     else if(x < -2*abs(y))
  997.     x = -1, y = 0;
  998.     else if(y < -2*abs(x))
  999.     x = 0, y = -1;
  1000.     else
  1001.     x = sgn(x), y = sgn(y);
  1002.  
  1003.     if(x == 0 && y == 0)    /* map click on player to "rest" command */
  1004.     return '.';
  1005.  
  1006.     x = xytod(x, y);
  1007.     if(mod == CLICK_1) {
  1008.     return (flags.num_pad ? ndir[x] : sdir[x]);
  1009.     } else {
  1010.     return (sdir[x] - 'a' + 'A'); /* run command */
  1011.     }
  1012. }
  1013.  
  1014. STATIC_OVL char *
  1015. parse()
  1016. {
  1017. #ifdef LINT    /* static char in_line[COLNO]; */
  1018.     char in_line[COLNO];
  1019. #else
  1020.     static char in_line[COLNO];
  1021. #endif
  1022.     register int foo;
  1023.     boolean prezero = FALSE;
  1024.  
  1025.     multi = 0;
  1026.     flags.move = 1;
  1027.     flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */
  1028.  
  1029.     if (!flags.num_pad || (foo = readchar()) == 'n')
  1030.         for (;;) {
  1031.         foo = readchar();
  1032.         if (foo >= '0' && foo <= '9') {
  1033.             multi = 10 * multi + foo - '0';
  1034.             if (multi < 0 || multi > LARGEST_INT) multi = LARGEST_INT;
  1035.             if (multi > 9) {
  1036.             clear_nhwindow(WIN_MESSAGE);
  1037.             Sprintf(in_line, "Count: %d", multi);
  1038.             pline(in_line);
  1039.             mark_synch();
  1040.             }
  1041.             last_multi = multi;
  1042.             if (!multi && foo == '0') prezero = TRUE;
  1043.         } else break;    /* not a digit */
  1044.         }
  1045.  
  1046.     if (foo == '\033') {   /* esc cancels count (TH) */
  1047.         clear_nhwindow(WIN_MESSAGE);
  1048.         multi = last_multi = 0;
  1049. # ifdef REDO
  1050.     } else if (foo == DOAGAIN || in_doagain) {
  1051.         multi = last_multi;
  1052.     } else {
  1053.         last_multi = multi;
  1054.         savech(0);    /* reset input queue */
  1055.         savech((char)foo);
  1056. # endif
  1057.     }
  1058.  
  1059.     if (multi) {
  1060.         multi--;
  1061.         save_cm = in_line;
  1062.     } else {
  1063.         save_cm = NULL;
  1064.     }
  1065.     in_line[0] = foo;
  1066.     in_line[1] = '\0';
  1067.     if (foo == 'g' || foo == 'G' || (flags.num_pad && foo == '5') ||
  1068.         foo == 'm' || foo == 'M') {
  1069.         foo = readchar();
  1070. #ifdef REDO
  1071.         savech((char)foo);
  1072. #endif
  1073.         in_line[1] = foo;
  1074.         in_line[2] = 0;
  1075.     }
  1076.     clear_nhwindow(WIN_MESSAGE);
  1077.     if (prezero) in_line[0] = '\033';
  1078.     return(in_line);
  1079. }
  1080.  
  1081. #endif /* OVL0 */
  1082. #ifdef OVLB
  1083.  
  1084. #ifdef UNIX
  1085. static
  1086. void
  1087. end_of_input()
  1088. {
  1089.     exit_nhwindows("End of input?");
  1090. #ifndef NOSAVEONHANGUP
  1091.     if(!hu) {
  1092.         hu = TRUE;
  1093.         (void) dosave0();
  1094.     }
  1095. #endif
  1096.     clearlocks();
  1097.     terminate(0);
  1098. }
  1099. #endif
  1100.  
  1101. #endif /* OVLB */
  1102. #ifdef OVL0
  1103.  
  1104. char
  1105. readchar()
  1106. {
  1107.     register int sym;
  1108.     int x, y, mod;
  1109.  
  1110. #ifdef REDO
  1111.     sym = in_doagain ? Getchar() : nh_poskey(&x, &y, &mod);
  1112. #else
  1113.     sym = Getchar();
  1114. #endif
  1115.  
  1116. #ifdef UNIX
  1117. # ifdef NR_OF_EOFS
  1118.     if (sym == EOF) {
  1119.         register int cnt = NR_OF_EOFS;
  1120.       /*
  1121.        * Some SYSV systems seem to return EOFs for various reasons
  1122.        * (?like when one hits break or for interrupted systemcalls?),
  1123.        * and we must see several before we quit.
  1124.        */
  1125.         do {
  1126.         clearerr(stdin);    /* omit if clearerr is undefined */
  1127.         sym = Getchar();
  1128.         } while (--cnt && sym == EOF);
  1129.     }
  1130. # endif /* NR_OF_EOFS */
  1131.     if (sym == EOF)
  1132.         end_of_input();
  1133. #endif /* UNIX */
  1134.  
  1135.     if(sym == 0) /* click event */
  1136.         sym = click_to_cmd(x, y, mod);
  1137.     return((char) sym);
  1138. }
  1139. #endif /* OVL0 */
  1140.  
  1141. /*cmd.c*/
  1142.